import asyncio
import json
import logging
import time
import re
from typing import List, Dict, Any

from redis import asyncio as aioredis
from redis.exceptions import RedisError

from DbServer.DbMainServer import DbMainServer
from wxauto import WeChat

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

logger = logging.getLogger(__name__)

# redis地址
redis_url = "redis://127.0.0.1:6379"
# 数据队列
queue_key = "autoText"

# 微信实例
wx = WeChat()
Dms = DbMainServer()

# 连接状态和重试配置
redis_connected = False
MAX_RETRIES = 5
RETRY_DELAY = 5  # 秒
# 微信操作超时时间（秒）
WX_OPERATION_TIMEOUT = 30


def stripStr(s: str) -> str:
    s = s.strip("\n")
    s = s.strip()
    return s


def splitString(s: str, spStr1: str, spStr2: str) -> str:
    """安全地分割字符串，添加了异常处理"""
    try:
        index1 = s.index(spStr1) + len(spStr1)
        index2 = s.index(spStr2)
        return s[index1:index2]
    except ValueError:
        logger.error(f"字符串分割失败，找不到分隔符: {s}")
        return ""


async def send_wechat_msg(msg: str, receiver: str, at: str = None) -> bool:
    """带超时控制的微信消息发送函数"""
    loop = asyncio.get_running_loop()

    try:
        # 使用run_in_executor在单独的线程中执行同步操作
        future = loop.run_in_executor(None, lambda: wx.SendMsg(msg, receiver, at=at))

        # 添加超时控制
        await asyncio.wait_for(future, timeout=WX_OPERATION_TIMEOUT)
        logger.info(f"微信消息发送成功: 接收者={receiver}, 内容长度={len(msg)}")
        return True

    except asyncio.TimeoutError:
        logger.error(f"微信消息发送超时: 接收者={receiver}, 内容长度={len(msg)}")
        return False
    except Exception as e:
        logger.error(f"微信消息发送失败: {str(e)}, 接收者={receiver}")
        return False


async def process_task(task_data: str) -> None:
    """处理Redis队列中的任务"""
    try:
        logger.info(f"开始处理任务: {task_data[:50]}...")
        task = json.loads(task_data)
        receiver = task.get('receiver')
        msg = task.get('msg')
        atUser = task.get('at')

        if not receiver or not msg:
            logger.error(f"无效的任务数据: {task_data[:30]}...")
            return

        if not isinstance(receiver, str) or not isinstance(msg, str):
            logger.error(f"无效的参数类型: receiver={type(receiver)}, msg={type(msg)}")
            return
        if isinstance(receiver, str) and isinstance(msg, str):
            wx.SendMsg(msg, receiver, at=atUser)
            logger.info("处理成功！")
        else:
            logger.error(f"无效的参数类型: receiver={receiver}, msg={msg}")

        # 尝试发送微信消息，最多重试3次
        # for attempt in range(3):
        #     success = await send_wechat_msg(msg, receiver, atUser)
        #     if success:
        #         break
        #     else:
        #         logger.warning(f"微信消息发送失败，尝试重试 ({attempt + 1}/3)")
        #         await asyncio.sleep(2)  # 短暂等待后重试
        # else:
        #     logger.error(f"微信消息发送失败，达到最大重试次数: {receiver}")

    except json.JSONDecodeError as e:
        logger.error(f"JSON解析错误: {task_data[:30]}... - {str(e)}")
    except Exception as e:
        logger.error(f"处理任务时发生未知错误: {str(e)}")


def process_messages(messages) -> None:
    """处理从微信获取的消息列表"""
    if not messages:
        return

    for message in messages:

        # for attr, value in vars(message).items():
        #     print(f"获取到属性值-----{attr}, {value}")

        try:

            sender = message.sender
            content = message.content
            msg_type = message.type

            if not sender or not content:
                logger.warning(f"不完整的消息: {message}")
                continue

            re_time = time.time()

            if msg_type == "friend":
                # 提取项目名称
                refer_content_text = splitString(content, "项目名称：", "项目金额：")
                refer_content_text = stripStr(refer_content_text)
                logger.info(f'收到好友回复: {sender} - {refer_content_text[:30]}...')

                if refer_content_text:
                    Dms.updatePushMsgByContent(content, sender, re_time, refer_content_text)
            else:
                logger.debug(f'收到其他类型消息: {msg_type} - {content[:30]}...')

        except Exception as e:
            logger.error(f"处理消息时发生未知错误: {str(e)}")


async def listen_window(chat_name: str) -> None:
    """监听指定微信聊天窗口的消息"""
    retries = 0
    while True:
        try:
            wx.AddListenChat(who=chat_name, savepic=False, savefile=False, savevoice=False)
            logger.info(f"开始监听微信聊天: {chat_name}")
            retries = 0  # 重置重试计数

            while True:
                try:
                    messages = wx.GetListenMessage(who=chat_name)
                    process_messages(messages)
                    await asyncio.sleep(3)  # 避免过于频繁地获取消息

                except Exception as e:
                    logger.error(f"获取微信消息时发生错误: {str(e)}")
                    await asyncio.sleep(3)  # 短暂等待后重试

        except Exception as e:
            retries += 1
            if retries > MAX_RETRIES:
                logger.critical(f"监听微信聊天 {chat_name} 达到最大重试次数，退出监听")
                break

            logger.error(f"监听微信聊天 {chat_name} 失败，尝试重新连接 ({retries}/{MAX_RETRIES}): {str(e)}")
            await asyncio.sleep(RETRY_DELAY * retries)  # 指数退避重试


async def pushMain() -> None:
    """主函数：监听Redis消息队列并处理消息"""
    global redis_connected

    while True:
        try:
            # 建立Redis连接
            async with aioredis.Redis.from_url(redis_url) as redis:
                redis_connected = True
                logger.info("Redis连接成功，开始监听消息队列")

                while True:
                    try:
                        # 从队列获取消息，设置5秒超时
                        task = await redis.brpop([queue_key], timeout=5)
                        if task and len(task) >= 2:
                            await process_task(task[1].decode('utf-8'))

                    except asyncio.CancelledError:
                        logger.info("收到停止信号，正在关闭Redis连接...")
                        raise  # 重新抛出异常，以便退出外层循环
                    except RedisError as e:
                        logger.error(f"Redis操作错误: {str(e)}")
                        redis_connected = False
                        raise  # 重新抛出异常，触发重连
                    except Exception as e:
                        logger.error(f"处理消息时发生未知错误: {str(e)}")
                        await asyncio.sleep(1)

        except RedisError as e:
            redis_connected = False
            logger.error(f"Redis连接错误: {str(e)}")
            await asyncio.sleep(RETRY_DELAY)  # 等待后重试
        except asyncio.CancelledError:
            break
        except Exception as e:
            logger.error(f"消息队列服务发生未知错误: {str(e)}")
            await asyncio.sleep(RETRY_DELAY)

    redis_connected = False
    logger.info("Redis消息队列服务已关闭")


async def listenChatMain() -> None:
    """监听多个微信聊天窗口的主函数"""
    chat_names = ["愿无岁月可回头", "东小政消息测试"]
    tasks = [asyncio.create_task(listen_window(name)) for name in chat_names]

    try:
        await asyncio.gather(*tasks)
    except asyncio.CancelledError:
        logger.info("微信监听任务被取消")
        for task in tasks:
            task.cancel()
        await asyncio.gather(*tasks, return_exceptions=True)


async def status_monitor() -> None:
    """监控程序状态并记录日志"""
    while True:
        try:
            status = {
                "redis_connected": redis_connected,
                "time": time.strftime("%Y-%m-%d %H:%M:%S"),
                "memory_usage": "TODO: 添加内存使用监控"
            }
            logger.debug(f"程序状态: {json.dumps(status)}")
            await asyncio.sleep(60)  # 每分钟记录一次状态
        except Exception as e:
            logger.error(f"状态监控错误: {str(e)}")
            await asyncio.sleep(30)


async def main() -> None:
    """程序入口点，管理所有异步任务"""
    logger.info("程序启动，开始初始化...")

    # 创建任务
    push_task = asyncio.create_task(pushMain())
    chat_task = asyncio.create_task(listenChatMain())
    monitor_task = asyncio.create_task(status_monitor())

    tasks = [push_task, chat_task, monitor_task]

    try:
        # 等待所有任务完成（实际上不会完成，除非被取消）
        await asyncio.gather(*tasks)
    except KeyboardInterrupt:
        logger.info("程序被用户中断，开始优雅关闭...")
    except Exception as e:
        logger.critical(f"程序发生致命错误: {str(e)}")
    finally:
        # 取消所有任务并等待它们完成清理
        for task in tasks:
            task.cancel()

        await asyncio.gather(*tasks, return_exceptions=True)
        logger.info("程序已优雅关闭")


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logger.info("程序被用户中断")
    except Exception as e:
        logger.error(f"程序异常退出: {str(e)}")
